package com.way.filemanager.providers;

import android.content.Context;
import android.database.MatrixCursor;
import android.os.StatFs;
import android.os.storage.StorageVolume;
import android.util.Log;

import com.way.filemanager.model.FileSystemObject;
import com.way.filemanager.model.ParentDirectory;
import com.way.filemanager.navigation.MyFileManager.FileOrder;
import com.way.filemanager.preferences.FileManagerSettings;
import com.way.filemanager.preferences.Preferences;
import com.way.filemanager.util.CommonFunc;
import com.way.filemanager.util.CommonIdDef;
import com.way.filemanager.util.FileHelper;
import com.way.filemanager.util.FileInfo;
import com.way.filemanager.util.StorageHelper;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;

public class FilelistManager {

    private static final String TAG = "FilelistManager";
    Context mActivity;
    boolean mIsScaning = false;
    boolean mForceStop = false;
    StorageVolume[] mVolumes;
    long []mTypeSize = new long [CommonIdDef.CATEGORY_ITEM_ID_MAX -CommonIdDef.CATEGORY_ITEM_ID_BASE];
    long []mScanningTypeSize = new long [CommonIdDef.CATEGORY_ITEM_ID_MAX -CommonIdDef.CATEGORY_ITEM_ID_BASE];
    int []mScanningTypeCount = new int [CommonIdDef.CATEGORY_ITEM_ID_MAX -CommonIdDef.CATEGORY_ITEM_ID_BASE];
    long mTotleMemory;
    long mAvailMemory;
    int mCurrentWorkType;
    ChangeStatusCb mChangeStatusCb;
    ChangeStatusCb mMainViewCb;
    int lSelectedCount = 0;

    private List<FileInfo> mPicFileList = new ArrayList<FileInfo>();
    private List<FileInfo> mVidFileList = new ArrayList<FileInfo>();
    private List<FileInfo> mMusicFileList = new ArrayList<FileInfo>();
    private List<FileInfo> mApkFileList = new ArrayList<FileInfo>();
    private List<FileInfo> mZipFileList = new ArrayList<FileInfo>();
    private List<FileInfo> mTextFileList = new ArrayList<FileInfo>();
    private List<FileInfo> mWorkingList = new ArrayList<FileInfo>();


    public FilelistManager(Context m)
    {
        mActivity = m;
        mTotleMemory = 0;
        mAvailMemory = 0;
        mVolumes = StorageHelper.getStorageVolumes(mActivity);
        for(StorageVolume root : mVolumes)
        {
            StatFs sf = null;
            try {
                 sf = new StatFs(root.getPath());
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            }

            if(sf != null)
            {
                long blockSize = sf.getBlockSize();
                long blockCount = sf.getBlockCount();
                long availCount = sf.getAvailableBlocks();
                mTotleMemory += blockSize*blockCount;
                mAvailMemory += availCount*blockSize;
                //Log.d(TAG, "block大小:"+ blockSize+",block数目:"+ blockCount+",总大小:"+blockSize*blockCount/1024+"KB");
                //Log.d(TAG, "可用的block数目：:"+ availCount+",剩余空间:"+ availCount*blockSize/1024+"KB");
            }
        }

        //FileListSQLiteOpenHelper mOpenHelper = new FileListSQLiteOpenHelper(m);
    }

    public void StartRun()
    {
        mIsScaning = true;
        mForceStop = false;

        Thread mThread = new Thread()
        {
            @SuppressWarnings("deprecation")
            @Override
            public void run()
            {
                if (mVolumes != null && mVolumes.length > 0) {

                    long temp = System.currentTimeMillis();
                    List<FileInfo> lstGetting =new ArrayList<FileInfo>();
                    for(int index =0;index < mScanningTypeSize.length;index++)
                    {
                        mScanningTypeSize[index] = 0;
                        mScanningTypeCount[index] = 0;
                    }

                    for(StorageVolume root:mVolumes)
                    {
                        //Log.v(TAG, "root.getPath():"+ root.getPath());
                        temp = System.currentTimeMillis();
                        GetFiles(root.getPath(),true,lstGetting,mScanningTypeSize);
                        Log.v(TAG, "time:"+(System.currentTimeMillis()-temp));
                    }
                    //
                    //sort the lstGetting by ASC mode,need by FileListSQLiteOpenHelper.sync
                    sortByFullPath(lstGetting);
                    for(FileInfo path:lstGetting)
                    {
                        List<FileInfo> tempList = getFileList(path.mType);
                        if(tempList != null)
                        {
                            mTypeSize[path.mType - CommonIdDef.CATEGORY_ITEM_ID_BASE] += path.GetFileSize();
                            tempList.add(path);
                        }
                    }
                    mIsScaning = false;
                    FileSyncDb(null,lstGetting,true);
                }
                mForceStop = false;
            }
        };
        mThread.start();

    }
    public boolean isScaning()
    {
        return mIsScaning;

    }
    public void ForceStopScan()
    {
        mForceStop = true;

    }
    public void ForceRefreshWorkingList()
    {
        mWorkingList.clear();
        mWorkingList.addAll(getFileList(mCurrentWorkType));
        sort();
    }

    private void GetFiles(String Path,boolean IsIterative,List<FileInfo> lstGetting,long [] filesize)
    {
        File[] files =new File(Path).listFiles();
        if((files == null)||mForceStop)
            return ;
        List<FileInfo> filesName =new ArrayList<FileInfo>();
        List<String>  filesPath =new ArrayList<String>();
        for (File f:files)
        {
            if (f.isFile())
            {
                String path =f.getName();
                if(path.equalsIgnoreCase(".nomedia"))
                {
                    filesName.clear();
                    filesPath.clear();
                    break;
                }
                int type = CommonFunc.getFileType(path);
                //f.length();
                if(type != 0)
                {
                    FileSystemObject fileObj = FileHelper.createFileSystemObject(f);
                    FileInfo fileinfo= new FileInfo(fileObj,type);
                    filesName.add(fileinfo);
                }
            }
            else if (!IgnoreDirectory.isNeedIgnore(f))
            {
                filesPath.add(f.getPath());
            }
        }
        lstGetting.addAll(filesName);

        for(FileInfo path:filesName)
        {
            filesize[path.mType - CommonIdDef.CATEGORY_ITEM_ID_BASE] += path.GetFileSize();
            mScanningTypeCount[path.mType - CommonIdDef.CATEGORY_ITEM_ID_BASE]++;
        }

        if (IsIterative)
        {
            for(String path:filesPath)
            {
                GetFiles(path, IsIterative,lstGetting,filesize);
            }
        }
    }
    public int GetFileCount(int type)
    {
        if(mIsScaning)
            return mScanningTypeCount[type - CommonIdDef.CATEGORY_ITEM_ID_BASE];

        return getFileList(type).size();
    }
    public int GetWorkingFileCount()
    {
        return mWorkingList.size();
    }
    public long GetTotleSDSize()
    {
        return mTotleMemory;
    }
    public long GetTotleAvailSize()
    {
        return mAvailMemory;
    }
    public String GetFileName(int type,int pos)
    {
        List<FileInfo> lTemp = getFileList(type);
        if((lTemp != null)&&(lTemp.size() > pos))
        {
            FileInfo t = lTemp.get(pos);
            return t.GetFileName();
        }
        return null;
    }
    public long GetTypeSize(int type)
    {
        final long []typesize;
        if(mIsScaning)
            typesize = mScanningTypeSize;
        else
            typesize = mTypeSize;

        if((type >= CommonIdDef.CATEGORY_ITEM_ID_BASE)&&(type < CommonIdDef.CATEGORY_ITEM_ID_MAX))
            return typesize[type - CommonIdDef.CATEGORY_ITEM_ID_BASE];
        else
            return 0;
    }
    public FileInfo GetFileInfo(int type, int pos)
    {
        List<FileInfo> lTemp = getFileList(type);
        if(lTemp != null)
            return lTemp.get(pos);
        else
            return null;
    }
    public FileInfo getCurrentFileInfo(int pos)
    {
        if(mWorkingList != null)
            return mWorkingList.get(pos);
        else
            return null;
    }
    public List<FileInfo> getFileList(int type)
    {
        switch(type)
        {
            case CommonIdDef.CATEGORY_ITEM_ID_PICTURE:
                return mPicFileList;
            case CommonIdDef.CATEGORY_ITEM_ID_MUSIC:
                return mMusicFileList;
            case CommonIdDef.CATEGORY_ITEM_ID_VIDEO:
                return mVidFileList;
            case CommonIdDef.CATEGORY_ITEM_ID_PACKAGE:
                return mApkFileList;
            case CommonIdDef.CATEGORY_ITEM_ID_TEXT:
                return mTextFileList;
            case CommonIdDef.CATEGORY_ITEM_ID_ZIP:
                return mZipFileList;
            case CommonIdDef.CATEGORY_ITEM_ID_Search:
                return getSearchList();
            case CommonIdDef.CATEGORY_ITEM_ID_Select:
                return getSelectList();
            default:
                break;
        }
        return null;
    }
    public void startSearch(int type,ChangeStatusCb cb)
    {
        mChangeStatusCb = cb;
        mCurrentWorkType = CommonIdDef.CATEGORY_ITEM_ID_Search;
        mWorkingList.clear();
        mWorkingList.addAll(getFileList(type));
        sort();
    }
    public void setMainViewCb(ChangeStatusCb cb)
    {
        mMainViewCb = cb;
    }
    public  List<FileInfo> SearchString(int type,String key)
    {
        //bug110870
        String newKey = key.toUpperCase(Locale.getDefault());
        List<FileInfo> temp = getFileList(type);
        mWorkingList.clear();
        for(FileInfo m:temp)
        {
            //bug110870
            if(m.mFileObj.getName().toUpperCase(Locale.getDefault()).contains(newKey))
                mWorkingList.add(m);
        }
        return mWorkingList;
    }
    public List<FileInfo> getSearchList()
    {
        return mWorkingList;
    }

    public void sortAllType()
    {
//        sort(CommonIdDef.CATEGORY_ITEM_ID_PICTURE);
//        sort(CommonIdDef.CATEGORY_ITEM_ID_MUSIC);
//        sort(CommonIdDef.CATEGORY_ITEM_ID_VIDEO);
//        sort(CommonIdDef.CATEGORY_ITEM_ID_PACKAGE);
//        sort(CommonIdDef.CATEGORY_ITEM_ID_TEXT);
//        sort(CommonIdDef.CATEGORY_ITEM_ID_ZIP);
          sort();
    }

    public void sort()
    {
        final boolean showDirsFirst = true;
        FileOrder mOrder = CommonFunc.loadCateorySaved(mActivity);
        final int sortmode = CommonFunc.fileOrder2Index(mOrder);
        Collections.sort(mWorkingList, new Comparator<FileInfo>() {
            @Override
            public int compare(FileInfo lhs, FileInfo rhs) {
                // Parent directory always goes first
                boolean isLhsParentDirectory = lhs.GetFileSystemObject() instanceof ParentDirectory;
                boolean isRhsParentDirectory = rhs.GetFileSystemObject() instanceof ParentDirectory;
                if (isLhsParentDirectory || isRhsParentDirectory) {
                    if (isLhsParentDirectory && isRhsParentDirectory) {
                        return 0;
                    }
                    return (isLhsParentDirectory) ? -1 : 1;
                }

                // Need to sort directory first?
                if (showDirsFirst) {
                    boolean isLhsDirectory = FileHelper.isDirectory(lhs.GetFileSystemObject());
                    boolean isRhsDirectory = FileHelper.isDirectory(rhs.GetFileSystemObject());
                    if (isLhsDirectory || isRhsDirectory) {
                        if (isLhsDirectory && isRhsDirectory) {
                            // Apply sort mode
                            return FileHelper.doCompare(lhs.GetFileSystemObject(), rhs.GetFileSystemObject(), sortmode);
                        }
                        return (isLhsDirectory) ? -1 : 1;
                    }
                }

                // Apply sort mode
                return FileHelper.doCompare(lhs.GetFileSystemObject(), rhs.GetFileSystemObject(), sortmode);
            }

        });
    }
    void sortByFullPath(List<FileInfo> lstFileList)
    {
        Collections.sort(lstFileList, new Comparator<FileInfo>() {
            @Override
            public int compare(FileInfo lhs, FileInfo rhs) {
                return lhs.GetFullPath().compareToIgnoreCase(rhs.GetFullPath());

            }

        });
    }

    public void startSelect(int type,ChangeStatusCb cb)
    {
        mChangeStatusCb = cb;
        mCurrentWorkType = CommonIdDef.CATEGORY_ITEM_ID_Select;
        lSelectedCount = 0;
        mWorkingList.clear();
        mWorkingList.addAll(getFileList(type));
        for(FileInfo m:mWorkingList)
        {
            m.SetFileSelect(false);
        }
        sort();
    }
    public List<FileInfo> getSelectList()
    {
        return mWorkingList;
    }

    public void  SelectedAdd()
    {
        lSelectedCount++;
        if(lSelectedCount > mWorkingList.size())
            lSelectedCount = mWorkingList.size();
    }
    public void  SelectedDec()
    {
        lSelectedCount--;
        if(lSelectedCount <0)
            lSelectedCount = 0;
    }
    public void  SelectedAll()
    {
        for(FileInfo m:mWorkingList)
        {
            m.mSelected = true;
        }
        lSelectedCount= mWorkingList.size();
    }
    public void  UnSelectedAll()
    {
        for(FileInfo m:mWorkingList)
        {
            m.mSelected = false;
        }
        lSelectedCount = 0;
    }
    public int  GetSelectedCount()
    {
        return lSelectedCount;
    }

    public void startNormal(int type,ChangeStatusCb cb)
    {
        lSelectedCount = 0;
        mWorkingList.clear();
        mCurrentWorkType = type;
        mChangeStatusCb = cb;
        Preferences.getSharedPreferences();
        FileManagerSettings showHiddenPref = FileManagerSettings.SETTINGS_SHOW_HIDDEN;
        if(Preferences.getSharedPreferences().getBoolean(showHiddenPref.getId(),
                 ((Boolean) showHiddenPref.getDefaultValue()).booleanValue()))
        {
            mWorkingList.addAll(getFileList(type));
        }
        else
        {
            for(FileInfo m:getFileList(type))
            {
                if(!m.GetFileName().startsWith("."))
                    mWorkingList.add(m);
            }
        }
        sort();
    }
    public FileInfo[] GetSelectCurrentFileInfo()
    {
        FileInfo [] lTemp = new FileInfo[lSelectedCount];
        int i = 0;
        for(FileInfo m:mWorkingList)
        {
            if(m.mSelected)
            {
                lTemp[i++] = m;
            }
        }
        return lTemp;
    }
    public String[] GetSelectCurrentFileString()
    {
        String [] lTemp = new String[lSelectedCount];
        int i = 0;
        for(FileInfo m:mWorkingList)
        {
            if(m.mSelected)
            {
                lTemp[i++] = m.GetFullPath();
            }
        }
        return lTemp;
    }
    public List<String> GetWorkListFileString()
    {
        List<String> lTemp = new ArrayList<String>();
        for(FileInfo m:mWorkingList)
        {
            lTemp.add(m.GetFullPath()) ;
        }
        return lTemp;
    }
    public boolean syncDir(String path,boolean IsIterative,ChangeStatusCb cb)
    {
        final String localPath = path;
        final boolean localIsIterative = IsIterative;
        final ChangeStatusCb syncDirCb = cb;
        //Bug106060,scan twice
        if(mIsScaning)
            return false;
        mIsScaning = true;
        Log.v("rwei","syncDir:"+path);
        new Thread()
        {
            @Override
            public void run()
            {
                // Change to first storage volume
                List<FileInfo> lstGetting =new ArrayList<FileInfo>();
                Log.v(TAG, "syncDir localPath:" + localPath);
                for(int index =0;index < mScanningTypeSize.length;index++)
                    mScanningTypeSize[index] = 0;
                GetFiles(localPath,localIsIterative,lstGetting,mScanningTypeSize);

                for(int type = CommonIdDef.CATEGORY_ITEM_ID_BASE;type <CommonIdDef.CATEGORY_ITEM_ID_MAX;type++)
                {
                    List<FileInfo> lstdel = getFileList(type);
                    List<FileInfo> lstRec = new ArrayList<FileInfo>();
                    for(FileInfo m:lstdel)
                    {
                        File temp = new File(m.GetFullPath());
                        if(localIsIterative)
                        {
                            if((m.GetFilePath().equalsIgnoreCase(localPath))||
                                    m.GetFilePath().startsWith(localPath+File.separator)|| !temp.exists())
                            {
                                Log.v(TAG, "syncDir GetFullPath:" + m.GetFullPath());
                                mTypeSize[m.mType - CommonIdDef.CATEGORY_ITEM_ID_BASE] -= m.GetFileSize();
                                //lstdel.remove(m);
                                lstRec.add(m);
                            }
                        }else {
                            if((m.GetFilePath().equalsIgnoreCase(localPath))|| !temp.exists())
                            {
                                Log.v(TAG, "syncDir GetFullPath:" + m.GetFullPath());
                                mTypeSize[m.mType - CommonIdDef.CATEGORY_ITEM_ID_BASE] -= m.GetFileSize();
                                //lstdel.remove(m);
                                lstRec.add(m);
                            }
                        }
                    }
                    for(FileInfo m:lstRec)
                        lstdel.remove(m);
                }

                for(FileInfo m:lstGetting)
                {
                    List<FileInfo> tempList = getFileList(m.mType);
                    if(tempList != null)
                    {
                        mTypeSize[m.mType - CommonIdDef.CATEGORY_ITEM_ID_BASE] += m.GetFileSize();
                        tempList.add(m);
                        Log.v(TAG, "syncDir add:" + m.GetFullPath());
                    }
                }

                if(syncDirCb != null)
                    syncDirCb.FileListChanged(mCurrentWorkType);
                FileSyncDb(localPath,lstGetting,true);
                if(mChangeStatusCb != null)
                    mChangeStatusCb.FileListChanged(mCurrentWorkType);
                if(mMainViewCb != null)
                    mMainViewCb.FileListChanged(mCurrentWorkType);

                mIsScaning = false;
                mForceStop = false;
            }
        }.start();

        return false;
    }
    public interface ChangeStatusCb{
        void FileListChanged(int type);
    }

    public interface ScanFilesCb{
        void ScanFilesProcess(int lCount);
    }

    public int FileSyncDb(String path, List<FileInfo> lstInput,boolean IsIterative) {

        final MatrixCursor syncFileList = new MatrixCursor(FileListSQLiteOpenHelper.QUERY_COLUMNS);
        try {
            for (FileInfo item : lstInput) {
                Object[] rowContent = new Object[FileListSQLiteOpenHelper.QUERY_COLUMNS.length];
                rowContent[1] = item.GetFilePath();
                rowContent[2] = item.GetFullPath();
                rowContent[4] = item.GetFileName();
                rowContent[5] = item.GetModifyTime();
                rowContent[6] = item.GetModifyTime();
                syncFileList.addRow(rowContent);
            }

            FileListSQLiteOpenHelper mSql = new FileListSQLiteOpenHelper(mActivity);
            mSql.sync(path, syncFileList,IsIterative);

        } finally {
            syncFileList.close();
        }
        return 0;
    }
    public void ClearWorkingStatus()
    {
        mChangeStatusCb = null;
        mCurrentWorkType = CommonIdDef.CATEGORY_ITEM_ID_BASE;
        mWorkingList.clear();
    }
}
